﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Demo
{
    public class AnotherHybridLock : IDisposable
    {
        // 基元用户模式构造，Interlocked 使用
        private int _m = 0;
        //控制自旋
        private int _spinCount = 4000;
        //基元内核构造
        AutoResetEvent _lock1 = new AutoResetEvent(false);
        //那个线程拥有锁，以及拥有的次数
        private int _owningThreadId = 0, _recursion = 0;

        public void Enter()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            if (threadId == _owningThreadId) {
                _recursion++;
                return;
            }

            SpinWait spinWait = new SpinWait();
            for (int i = 0; i < _spinCount; i++)
            {

                if (Interlocked.CompareExchange(ref _m, 1, 0) == 0)
                {

                    goto GotLock;
                }
                //其他线程运行的机会，希望锁被释放
                spinWait.SpinOnce();
            }
            // 自旋结束了，但是 还是未获取锁，重试一次
            if (Interlocked.Increment(ref _m) > 1)
            {
                _lock1.WaitOne();//等待锁
                // 等待这个线程醒来，他拥有锁，设置状态返回。
            
            }
            GotLock:
            //一个线程获取锁后记录下，并且制定线程拥有一次锁。

            _owningThreadId = threadId;
            _recursion = 1;
        }

        public void Leave()
        {
            // 如果线程不拥有锁，表示有问题
            int threadId = Thread.CurrentThread.ManagedThreadId;

            if (threadId != _owningThreadId)
            {
                throw new Exception("locked not ");
            }

            if (--_recursion>0)
            {
                return;
            }
            _owningThreadId = 0; // 没有线程拥有锁
            // 没有线程等待直接返回
            if (Interlocked.Decrement(ref _m) == 0) return;

            // 有其他线程等待唤醒一个
            _lock1.Set();





        }


        public void Dispose()
        {
            _lock1.Dispose();
        }
    }
}
